/*************************************************************************
	> File Name: NfaHandler.hpp
	> Author: H.M. Lau
	> Mail: hm.lau@outlook.com
	> Created Time: 2023/10/25 19:32
 ************************************************************************/

#pragma once

#include <iostream>
#include <stack>
#include "reg_lexer.hpp"
#include <unordered_set>
#include <cassert>
#include <unordered_set>
#include "log.hpp"

namespace nfa
{
    const size_t BUF_SIZE = 256;
    enum Anchor { NONE, START, END, BOTH };
    enum Recv { EMPTY, CCL, EPSILON };
    std::vector<std::string> mapRecv = {
        "EMPTY",
        "CCL",
        "EPSILON"
    };

    class Nfa
    {
    public:
        Nfa ():_edge(Recv::EMPTY), _anchor(Anchor::NONE), _num(0),  _next1(nullptr), _next2(nullptr) {}

        void setEdge(Recv type)
        {
            _edge = type;
        }

        Recv getEdge() const
        {
            return _edge ;
        }

        void setNum(size_t num)
        {
            _num = num;
        }

        size_t getNum() const
        {
            return _num;
        }

        void clearState()
        {
            Nfa nfa;
            std::swap(*this, nfa);
        }

        void addToSet(uint8_t c)
        {
            _input_set.insert(c);
        }

        const std::unordered_set<uint8_t>& getSet() const
        {
            return _input_set;
        }

        void setComplement()
        {
            std::unordered_set<uint8_t> s;
            for (uint8_t i = 0; i < ASCII_COUNT; ++i) {
                if (_input_set.find(i) == _input_set.end()) {
                    s.insert(i);
                }
            }
            _input_set.swap(s);
        }

        void setAnchor(const Anchor anchor) 
        {
            _anchor = anchor;
        }

        Anchor getAnchor() const
        {
            return _anchor;
        }

        std::string getSetStr()
        {
            std::string str;
            str += "[ ";
            for (const auto& e : _input_set) {
                str += e;
                str += ' ';
            }
            str += ']';
            return str;
        }

        ~Nfa ()
        {
            delete _next1;
            delete _next2;
        }

    public:
        Recv _edge;
        Anchor _anchor;
        size_t _num;
        Nfa* _next1;
        Nfa* _next2;
        std::unordered_set<uint8_t> _input_set;
        static const size_t ASCII_COUNT = 127;
    };

    struct NfaPair {
        Nfa* _start;
        Nfa* _end;
        NfaPair ():_start(nullptr), _end(nullptr) {}
    };

}
